
;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          user.lisp
;;;; Purpose:       Audioscrobbler/lastfm User API.
;;;; Programmer:    Nicolas Lamirault <nicolas.lamirault@gmail.com>
;;;;
;;;; This file, part of audioscrobbler, is Copyright (c) 2007 by Nicolas Lamirault
;;;;
;;;; cl-audioscrobbler users are granted the rights to distribute and use this software
;;;; as governed by the terms of the MIT License :
;;;; http://www.opensource.org/licenses/mit-license.php
;;;;
;;;; *************************************************************************


(in-package :cl-audioscrobbler)


(defun retrieve-user-profile-information (username)
 "Information about the profile (eg: Name, Gender)."
 (get-xml-answer (format nil +user-profile-information+ username)))


(defun retrieve-user-top-artists (username)
 "50 most played artists from a music profile."
 (get-xml-answer (format nil +user-top-artists+  username)))


(defun retrieve-user-top-albums (username)
 "50 most played albums from a music profile."
 (get-xml-answer (format nil +user-top-albums+ username)))


(defun retrieve-user-top-tracks (username)
 "50 most played tracks from a music profile."
 (get-xml-answer (format nil +user-top-tracks+ username)))


(defun retrieve-user-top-tags (username)
 "50 most played tracks from a music profile."
 (get-xml-answer (format nil +user-top-tags+ username)))


(defun retrieve-user-top-tags-artist (username artist-name)
 "Tags most used on a specific artist."
 (get-xml-answer (format nil +user-top-tags-artist+ username artist-name)))


(defun retrieve-user-top-tags-album (username artist-name album-name)
 "Tags most used on a specific album."
 (get-xml-answer
  (format nil +user-top-tags-album+ username artist-name album-name)))


(defun retrieve-user-top-tags-track (username artist-name track-name)
 "Tags most used on a specific track."
 (get-xml-answer
  (format nil +user-top-tags-track+ username artist-name track-name)))


(defun retrieve-user-friends (username)
 "Friends added to this profile."
 (get-xml-answer (format nil +user-friends+ username)))


(defun retrieve-user-neighbours (username)
 "People with similar taste to this profile."
 (get-xml-answer (format nil +user-neighbours+ username)))


(defun retrieve-user-recent-tracks (username)
 "10 recently played tracks for this profile."
 (get-xml-answer (format nil +user-recent-tracks+ username)))


(defun retrieve-user-weekly-artists (username)
 "Most recent weekly artist chart."
 (get-xml-answer (format nil +user-weekly-artist+ username)))


(defun retrieve-user-weekly-albums (username)
 "Most recent weekly album chart."
 (get-xml-answer (format nil +user-weekly-album+ username)))


(defun retrieve-user-weekly-tracks (username)
 "Most recent weekly track chart."
 (get-xml-answer (format nil +user-weekly-track+ username)))


(defun retrieve-user-taste-o-meter (username another)
  "Similarity of this USERNAME to ANOTHER."
  (get-xml-answer (format nil +user-taste-o-meter+ username another)))


;; ----------------
;; API WebServices
;; ----------------


(defun get-profile (username)
 "Create a user profile from USERNAME."
 (let ((xmldoc (retrieve-user-profile-information username)))
   (make-instance 'profile
                  :id (third (car xmldoc))
                  :name username
                  :url (cadr (second xmldoc))
                  :registered (cadr (fifth xmldoc))
                  :age (cadr (sixth xmldoc))
                  :gender (cadr (seventh xmldoc))
                  :country (cadr (eighth xmldoc)))))


(defun get-user-top-artists (username)
 "Retrieve a list of most played artists by an user."
 (let ((xmldoc (retrieve-user-top-artists username)))
   (when (and (listp (cdr xmldoc))
              (listp (cadr xmldoc)))
     (loop for sexp in (cdr xmldoc)
        as name = (cadr (first (cdr sexp)))
        as mbid = (if (listp (second (cdr sexp)))
                      (cadr (second (cdr sexp)))
                      "")
        as playcount = (cadr (third (cdr sexp)))
        as rank = (cadr (fourth (cdr sexp)))
        as url = (cadr (fifth (cdr sexp)))
        collect (make-instance 'user-top-artist
                               :name name
                               :mbid mbid
                               :url url
                               :playcount playcount
                               :rank rank)))))


(defun get-user-top-albums (username)
 "Retrieve a list of most played music albums by an user."
 (let ((xmldoc (retrieve-user-top-albums username)))
   (when (and (listp (cdr xmldoc))
              (listp (cadr xmldoc)))
     (loop for sexp in (cdr xmldoc)
        as artist-name = (cadr (first (cdr sexp)))
        as name = (cadr (second (cdr sexp)))
        as mbid = (if (listp (third (cdr sexp)))
                      (cadr (third (cdr sexp)))
                      "")
        as playcount = (cadr (fourth (cdr sexp)))
        as rank = (cadr (fifth (cdr sexp)))
        as url = (cadr (sixth (cdr sexp)))
        as large = (cadr (first (cdr (seventh (cdr sexp)))))
        as medium = (cadr (second (cdr (seventh (cdr sexp)))))
        as small = (cadr (third (cdr (seventh (cdr sexp)))))
        collect (make-instance 'user-top-album
                               :name name
                               :artist-name artist-name
                               :mbid mbid
                               :url url
                               :playcount playcount
                               :rank rank
                               :small small :medium medium :large large)))))


(defun get-user-top-tracks (username)
 "Retrieve a list of most played music tracks by an user."
 (let ((xmldoc (retrieve-user-top-tracks username)))
   (when (and (listp (cdr xmldoc))
              (listp (cadr xmldoc)))
     (loop for sexp in (cdr xmldoc)
        as artist = (car (last (first (cdr sexp))))
        as name = (cadr (second (cdr sexp)))
        as playcount = (cadr (fourth (cdr sexp)))
        as rank = (cadr (fifth (cdr sexp)))
        as url = (cadr (sixth (cdr sexp)))
        collect (make-instance 'user-top-track
                               :artist-name artist
                               :name name
                               :playcount playcount
                               :rank rank
                               :url url)))))


(defun get-user-neighbours (username)
 "People with similar taste to this profile."
 (let ((xmldoc (retrieve-user-neighbours username)))
   (loop for sexp in (cdr xmldoc)
      as name = (third (first sexp))
      as url = (cadr (second sexp))
      as image = (cadr (third sexp))
      as match = (cadr (fourth sexp))
      collect (make-instance 'neighbour
                             :name name
                             :url url
                             :image image
                             :match match))))


(defun get-user-friends (username)
 "Friends added to this profile."
 (let ((xmldoc (retrieve-user-friends username)))
   (when (and (listp (cdr xmldoc))
              (listp (cadr xmldoc)))
     (loop for sexp in (cdr xmldoc)
        as name = (third (first sexp))
        as url = (cadr (second sexp))
        as image = (cadr (third sexp))
        as connection = (cadr (fourth sexp))
        collect (make-instance 'friend
                               :name name
                               :url url
                               :image image
                               :connection connection)))))



(defun get-user-top-tags (username)
  "A list of the most used tags by a music profile."
  (let ((xmldoc (retrieve-user-top-tags username)))
   (when (and (listp (cdr xmldoc))
              (listp (cadr xmldoc)))
     (loop for sexp in (cdr xmldoc)
        as name = (cadr (first (cdr sexp)))
        as url = (cadr (second sexp))
        as count = (cadr (third sexp))
        collect (make-instance 'tag :name name
                                    :url url
                                    :count count)))))


(defun get-user-recent-tracks (username)
  "A list of recently played tracks for this profile."
  (let ((xmldoc (retrieve-user-recent-tracks username)))
   (when (and (listp (cdr xmldoc))
              (listp (cadr xmldoc)))
     (loop for sexp in (cdr xmldoc)
        as artist = (cadr (second sexp))
        as track = (cadr (third sexp))
        as url = (cadr (sixth sexp))
        as date = (cadr (seventh sexp))
        collect (make-instance 'recent-track :name track
                                             :artist artist
                                             :url url
                                             :date date)))))


(defun get-user-taste-o-meter (username another)
  "A list of similarity of this USERNAME to ANOTHER user."
  (let ((xmldoc (retrieve-user-taste-o-meter username another)))
   (when (and (listp (cdr xmldoc))
              (listp (cadr xmldoc)))
     (let ((score (cadadr xmldoc))
           (artists (loop for sexp in (cdr (second (cdr xmldoc)))
                       collect (cadadr sexp))))
       (make-instance 'taste-o-meter :score score
                                     :first-user username
                                     :second-user another
                                     :artists artists)))))
       
           